package cn.sciento.boot.tenant.dto;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import cn.sciento.common.STongService;
import cn.sciento.core.redis.RedisHelper;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import cn.sciento.boot.tenant.constant.TenantInitProcessorType;
import cn.sciento.boot.tenant.constant.TenantInitType;
import cn.sciento.boot.tenant.hiam.domain.entity.TenantInitConfig;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

public class TenantInitConfigDTO {
  public static final String CACHE_KEY_PREFIX = "hiam:tenant-init";

  // 服务名称
  private String serviceName;

  // 处理器service名称
  private String processorCode;

  // 处理器名称
  private String processorName;

  // 处理类型
  private TenantInitProcessorType processorType;

  // 租客创建还是更新
  private TenantInitType initType;

  // 处理顺序
  private Integer orderSeq;
  
  private String remark;
  
  public TenantInitConfigDTO() {}
  
  public TenantInitConfigDTO(String serviceName, String processorCode, String processorName, TenantInitProcessorType processorType, TenantInitType initType, Integer orderSeq, String remark) {
    this.serviceName = serviceName;
    this.processorCode = processorCode;
    this.processorName = processorName;
    this.processorType = processorType;
    this.initType = initType;
    this.orderSeq = orderSeq;
    this.remark = remark;
  }
  
  public static TenantInitConfigDTO initInstance(TenantInitConfig tenantInitConfig) {
    TenantInitConfigDTO tenantInitConfigDTO = new TenantInitConfigDTO();
    BeanUtils.copyProperties(tenantInitConfig, tenantInitConfigDTO);
    tenantInitConfigDTO.setInitType(TenantInitType.valueOf(tenantInitConfig.getInitType()));
    tenantInitConfigDTO.setProcessorType(TenantInitProcessorType.valueOf(tenantInitConfig.getProcessorType()));
    tenantInitConfigDTO.setOrderSeq(tenantInitConfig.getOrderSeq().intValue());
    return tenantInitConfigDTO;
  }
  
  public void doCache(RedisHelper redisHelper) {
    redisHelper.setCurrentDatabase(STongService.Iam.REDIS_DB);
    redisHelper.hshPut(buildCacheKey(), buildCacheHashKey(), redisHelper.toJson(this));
    redisHelper.clearCurrentDatabase();
  }
  
  private String buildCacheKey() {
    Assert.notNull(this.initType, "init type cannot be null");
    Assert.notNull(this.processorType, "init processor type cannot be null.");
    return "hiam:tenant-init:" + this.initType + ":" + this.processorType;
  }
  
  private String buildCacheHashKey() {
    Assert.notNull(this.serviceName, "service name cannot be null.");
    Assert.notNull(this.processorCode, "processorCode name cannot be null.");
    return this.serviceName + ":" + this.processorCode;
  }
  
  public TenantInitConfigDTO doFetchCache(RedisHelper redisHelper) {
    redisHelper.setCurrentDatabase(STongService.Iam.REDIS_DB);
    String rawData = redisHelper.hshGet(buildCacheKey(), buildCacheHashKey());
    redisHelper.clearCurrentDatabase();
    if (StringUtils.isEmpty(rawData)) {
      return null;
    }
    return redisHelper.fromJson(rawData, TenantInitConfigDTO.class);
  }
  
  public List<TenantInitConfigDTO> doFetchCaches(RedisHelper redisHelper) {
    redisHelper.setCurrentDatabase(STongService.Iam.REDIS_DB);
    List<String> rawData = redisHelper.hshVals(buildCacheKey());
    redisHelper.clearCurrentDatabase();
    if (CollectionUtils.isEmpty(rawData)) {
      return Collections.emptyList();
    }
    List<TenantInitConfigDTO> resultList = rawData.parallelStream()
            .map(item -> redisHelper.fromJson(item, TenantInitConfigDTO.class)).collect(Collectors.toList());
    return resultList;
  }

  public static void clearCatch(RedisHelper redisHelper) {
    redisHelper.setCurrentDatabase(STongService.Iam.REDIS_DB);
    List<String> catchKeys = new ArrayList();
    List<TenantInitType> tenantInitTypes = Arrays.asList(TenantInitType.values());
    List<TenantInitProcessorType> tenantInitProcessorTypes = Arrays.asList(TenantInitProcessorType.values());
    tenantInitTypes.forEach((tenantInitType) -> {
      tenantInitProcessorTypes.forEach((tenantInitProcessorType) -> {
        catchKeys.add("hiam:tenant-init:" + tenantInitTypes + ":" + tenantInitProcessorTypes);
      });
    });
    redisHelper.delKeys(catchKeys);
    redisHelper.clearCurrentDatabase();
  }
  
  public String getServiceName() {
    return this.serviceName;
  }
  
  public TenantInitConfigDTO setServiceName(String serviceName) {
    this.serviceName = serviceName;
    return this;
  }
  
  public String getProcessorCode() {
    return this.processorCode;
  }
  
  public TenantInitConfigDTO setProcessorCode(String processorCode) {
    this.processorCode = processorCode;
    return this;
  }
  
  public TenantInitProcessorType getProcessorType() {
    return this.processorType;
  }
  
  public TenantInitConfigDTO setProcessorType(TenantInitProcessorType processorType) {
    this.processorType = processorType;
    return this;
  }
  
  public TenantInitType getInitType() {
    return this.initType;
  }
  
  public TenantInitConfigDTO setInitType(TenantInitType initType) {
    this.initType = initType;
    return this;
  }
  
  public String getProcessorName() {
    return this.processorName;
  }
  
  public TenantInitConfigDTO setProcessorName(String processorName) {
    this.processorName = processorName;
    return this;
  }
  
  public Integer getOrderSeq() {
    return this.orderSeq;
  }
  
  public TenantInitConfigDTO setOrderSeq(Integer orderSeq) {
    this.orderSeq = orderSeq;
    return this;
  }
  
  public String getRemark() {
    return this.remark;
  }
  
  public TenantInitConfigDTO setRemark(String remark) {
    this.remark = remark;
    return this;
  }
  
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    TenantInitConfigDTO that = (TenantInitConfigDTO)o;
    return (new EqualsBuilder())
      .append(this.serviceName, that.serviceName)
      .append(this.processorCode, that.processorCode)
      .append(this.processorName, that.processorName)
      .append(this.processorType, that.processorType)
      .append(this.initType, that.initType)
      .append(this.orderSeq, that.orderSeq)
      .append(this.remark, that.remark)
      .isEquals();
  }
  
  @Override
  public int hashCode() {
    return (new HashCodeBuilder(17, 37))
      .append(this.serviceName)
      .append(this.processorCode)
      .append(this.processorName)
      .append(this.processorType)
      .append(this.initType)
      .append(this.orderSeq)
      .append(this.remark)
      .toHashCode();
  }
  
  @Override
  public String toString() {
    return (new ToStringBuilder(this))
      .append("serviceName", this.serviceName)
      .append("processorCode", this.processorCode)
      .append("processorName", this.processorName)
      .append("processorType", this.processorType)
      .append("initType", this.initType)
      .append("orderSeq", this.orderSeq)
      .append("remark", this.remark)
      .toString();
  }
}
